﻿using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Quartz.Net.Model;
using Quartz.Impl;
using Quartz.Net.Core.Listener;
using Quartz.Impl.Matchers;
using Newtonsoft.Json;
using System.Collections.Specialized;
using Quartz.Net.Factory;

namespace Quartz.Net.Core
{
    public class QuartzHelper
    {

        private static object obj = new object();
        /// <summary>
        /// 通信方式
        /// </summary>
        private static string scheme = "tcp";
        /// <summary>
        /// ip地址
        /// </summary>
        private static string server = "localhost";
        /// <summary>
        /// 端口号
        /// </summary>
        private static string port = "80";
        /// <summary>
        /// 缓存任务所在程序集信息
        /// </summary>
        private static Dictionary<string, Assembly> AssemblyDict = new Dictionary<string, Assembly>();
        /// <summary>
        /// 调度服务的对象
        /// </summary>
        private static IScheduler scheduler = null;

        /// <summary>
        /// 所有可以运行的任务
        /// </summary>
        private static IEnumerable<Task_Quartz_JobTriggerModel> _currentTaskList = null;
        /// <summary>
        /// 所有可以运行的任务
        /// </summary>
        public static IEnumerable<Task_Quartz_JobTriggerModel> CurrentTaskList
        {
            set { }
            get
            {
                if (_currentTaskList == null)
                {
                    _currentTaskList = factoryClass.JobTriggerGetInfo().Where(m => m.VALID == "1");
                }
                return _currentTaskList;
            }
        }


        /// <summary>
        /// 初始化任务调度对象
        /// </summary>
        public static void InitScheduler()
        {
            try
            {
                lock (obj)
                {
                    if (scheduler == null)
                    {
                        #region quartz 实例配置
                        //NameValueCollection properties = new NameValueCollection();

                        //properties["quartz.scheduler.instanceName"] = "ExampleQuartzScheduler";

                        //properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";

                        //properties["quartz.threadPool.threadCount"] = "10";

                        //properties["quartz.threadPool.threadPriority"] = "Normal";

                        //properties["quartz.jobStore.misfireThreshold"] = "60000";

                        //properties["quartz.jobStore.type"] = "Quartz.Simpl.RAMJobStore, Quartz";

                        //properties["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz";

                        //properties["quartz.scheduler.exporter.port"] = "555";

                        //properties["quartz.scheduler.exporter.bindName"] = "QuartzScheduler";

                        //properties["quartz.scheduler.exporter.channelType"] = scheme;

                        //ISchedulerFactory factory = new StdSchedulerFactory(properties);

                        //scheduler = factory.GetScheduler();
                        #endregion
                        //// 配置文件的方式，配置quartz实例
                        ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
                        scheduler = schedulerFactory.GetScheduler();

                        //LogHelper.WriteLog("任务调度初始化成功！");
                    }
                }
            }
            catch (Exception ex)
            {
                //LogHelper.WriteLog("任务调度初始化失败！", ex);
                factoryClass.InsertRrrorlog(ex.Message, "任务调度初始化失败!", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 启用任务调度
        /// 启动调度时会把任务表中状态为“执行中”的任务加入到任务调度队列中
        /// </summary>
        public static void StartScheduler()
        {
            try
            {
                if (!scheduler.IsStarted)
                {
                    //添加全局监听
                    scheduler.ListenerManager.AddSchedulerListener(new mySchedulerListener());
                    myTriggerListener myTriggerListener1 = new myTriggerListener();
                    //myTriggerListener1.Name = "myTriggerListener";
                    myJobListener myJobListener1 = new myJobListener();
                    //myJobListener1.Name = "myJobListener";
                    scheduler.ListenerManager.AddTriggerListener(myTriggerListener1, GroupMatcher<TriggerKey>.AnyGroup());
                    scheduler.ListenerManager.AddJobListener(myJobListener1, GroupMatcher<JobKey>.AnyGroup());

                    scheduler.Start();
                    ///获取所有执行中的任务
                    List<Task_Quartz_JobTriggerModel> listTask = factoryClass.JobTriggerGetInfo().Where(m => m.VALID == "1" && m.RUNSTATUS != "3").ToList<Task_Quartz_JobTriggerModel>();
                    _currentTaskList = listTask;
                    if (listTask != null && listTask.Count > 0)
                    {
                        foreach (Task_Quartz_JobTriggerModel taskUtil in listTask)
                        {
                            try
                            {
                                ScheduleJob(taskUtil,false,1);
                            }
                            catch (Exception ex)
                            {
                                //LogHelper.WriteLog(string.Format("任务“{0}”启动失败！", taskUtil.TaskName), e);
                                factoryClass.InsertRrrorlog(ex.Message, string.Format("任务“{0}”启动失败！", taskUtil.JOBNAME), LogsStatus.Fatal);
                            }
                        }
                    }
                    Task_Quartz_JobTriggerModel ts = new Task_Quartz_JobTriggerModel();
                    ts.NGUID = "5957108f-0df9-4ce2-b202-1674e21c644c";
                    ts.JOBNAME = "jobts1";
                    ts.JOBGROUPNAME = "groupts1";
                    ts.TRIGGERNAME = "tri1";
                    ts.TRIGGERGROUPNAME = "groupts1";
                    ts.JOBCRON = "0/2 * * * * ?";
                    ts.VALID = "1";
                    ts.RUNSTATUS = "1";
                    ts.ISCHANGE = "0";
                    ScheduleJobLx(ts);
                    //LogHelper.WriteLog("任务调度启动成功！");
                }
            }
            catch (Exception ex)
            {
                //LogHelper.WriteLog("任务调度启动失败！", ex);
                factoryClass.InsertRrrorlog(ex.Message, "任务调度启动失败!", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 启用任务
        /// <param name="task">任务信息</param>
        /// <param name="isDeleteOldTask">是否删除原有任务</param>
        /// <returns>返回任务trigger</returns>
        /// </summary>
        public static void ScheduleJob(Task_Quartz_JobTriggerModel task, bool isDeleteOldTask = false, int n = 0)
        {
            //int n = 0;
            JobKey jk = new JobKey(task.JOBNAME, task.JOBGROUPNAME);
            if (isDeleteOldTask)
            {
                
                if (scheduler.CheckExists(jk))
                {
                    //先删除现有已存在任务
                    DeleteJob(task.JOBNAME.ToString(), task.JOBGROUPNAME);
                    n = 1;
                }
            }
            //验证是否正确的Cron表达式
            if (ValidExpression(task.JOBCRON))
            {
                if (n == 1)
                {
                    TriggerKey tk = new TriggerKey(task.TRIGGERNAME, task.TRIGGERGROUPNAME);
                    IJobDetail job = JobBuilder.Create<TestJob>()
                       .WithIdentity(jk)
                       .UsingJobData("jobDetails", JsonConvert.SerializeObject(task))
                       .UsingJobData("jobData", task.JOBPATH+task.JOBSNAME)
                       .Build();

                    ITrigger trigger = TriggerBuilder.Create()
                        .WithIdentity(tk)
                         .UsingJobData("triggerDetails", JsonConvert.SerializeObject(task))
                        .WithCronSchedule(task.JOBCRON)
                        .Build();

                    scheduler.ScheduleJob(job, trigger);
                }
                
                

            }
            else
            {
                //throw new Exception(task.JOBCRON + "不是正确的Cron表达式,无法启动该任务!");
                
                factoryClass.InsertRrrorlog(task.JOBCRON + "不是正确的Cron表达式,无法启动该任务!" + task.JOBNAME, task.JOBCRON + "不是正确的Cron表达式,无法启动该任务!", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        public static void ScheduleJobLx(Task_Quartz_JobTriggerModel task, bool isDeleteOldTask = false)
        {
            if (isDeleteOldTask)
            {
                //先删除现有已存在任务
                DeleteJob(task.JOBNAME.ToString(),task.JOBGROUPNAME);
            }
            //验证是否正确的Cron表达式
            if (ValidExpression(task.JOBCRON))
            {

                JobKey jk = new JobKey(task.JOBNAME, task.JOBGROUPNAME);
                TriggerKey tk = new TriggerKey(task.TRIGGERNAME, task.TRIGGERGROUPNAME);
                IJobDetail job = JobBuilder.Create<JobLx>()
                  .UsingJobData("jobDetails", JsonConvert.SerializeObject(task))
                   .UsingJobData("jobData", task.JOBPATH)
                   .Build();

                ITrigger trigger = TriggerBuilder.Create()
                    .WithIdentity(tk)
                     .UsingJobData("triggerDetails", JsonConvert.SerializeObject(task))
                    .WithCronSchedule(task.JOBCRON)
                    .Build();

                scheduler.ScheduleJob(job, trigger);

            }
            else
            {
                //throw new Exception(task.JOBCRON + "不是正确的Cron表达式,无法启动该任务!");
                factoryClass.InsertRrrorlog(task.JOBCRON + "不是正确的Cron表达式,无法启动该任务!" + task.JOBNAME, task.JOBCRON + "不是正确的Cron表达式,无法启动该任务!", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }


        /// <summary>
        /// 立即启用任务
        /// <param name="task">任务信息</param>
        /// <param name="isDeleteOldTask">是否删除原有任务</param>
        /// <returns>返回任务trigger</returns>
        /// </summary>
        public static void ScheduleJobLj(Task_Quartz_JobTriggerModel task)
        {
            //int n = 0;
            
            JobKey jk = new JobKey(task.JOBNAME, task.JOBGROUPNAME);
            TriggerKey tk = new TriggerKey(task.TRIGGERNAME, task.TRIGGERGROUPNAME);
            IJobDetail job = JobBuilder.Create<TestJob>()
                       .WithIdentity(jk)
                       .UsingJobData("jobDetails", JsonConvert.SerializeObject(task))
                       .UsingJobData("jobData", task.JOBPATH + task.JOBSNAME)
                       .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(tk)
                 .UsingJobData("triggerDetails", JsonConvert.SerializeObject(task))
                .WithSimpleSchedule(
                x => x.WithIntervalInSeconds(1).WithRepeatCount(0)
                )
                .Build();

            scheduler.ScheduleJob(job, trigger);

        }
        /// <summary>
        /// 初始化 远程Quartz服务器中的，各个Scheduler实例。
        /// 提供给远程管理端的后台，用户获取Scheduler实例的信息。
        /// </summary>
        public static void InitRemoteScheduler()
        {
            try
            {
                NameValueCollection properties = new NameValueCollection();

                properties["quartz.scheduler.instanceName"] = "ExampleQuartzScheduler";
                // 设置线程池
                properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
                properties["quartz.threadPool.threadCount"] = "5";
                properties["quartz.threadPool.threadPriority"] = "Normal";

                // 远程输出配置
                //properties["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz";
                //properties["quartz.scheduler.exporter.port"] = "8008";
                //properties["quartz.scheduler.exporter.bindName"] = "QuartzScheduler";
                //properties["quartz.scheduler.exporter.channelType"] = "tcp";
                properties["quartz.scheduler.proxy"] = "true";

                properties["quartz.scheduler.proxy.address"] = string.Format("{0}://{1}:{2}/QuartzScheduler", scheme, server, port);

                ISchedulerFactory sf = new StdSchedulerFactory(properties);

                scheduler = sf.GetScheduler();
            }
            catch (Exception ex)
            {
                //LogHelper.WriteLog("初始化远程任务管理器失败" + ex.StackTrace);
                factoryClass.InsertRrrorlog(ex.Message, "初始化远程任务管理器失败!", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }


        /// <summary>
        /// 删除现有任务
        /// </summary>
        /// <param name="JobKey"></param>
        public static void DeleteJob(string name, string group)
        {
            JobKey jk = new JobKey(name, group);
            try
            {
                
                if (scheduler.CheckExists(jk))
                {
                    //任务已经存在则删除
                    scheduler.DeleteJob(jk);
                    factoryClass.JobDeleted(jk.Name);
                    Console.WriteLine(jk.Name+":Job任务调度删除");
                    //LogHelper.WriteLog(string.Format("任务“{0}”已经删除", JobKey));
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, jk.Name + ":Job任务调度删除失败", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }
        /// <summary>
        /// 删除现有任务暂停
        /// </summary>
        /// <param name="JobKey"></param>
        public static void DeleteJobZt(string name, string group)
        {
            JobKey jk = new JobKey(name, group);
            try
            {

                if (scheduler.CheckExists(jk))
                {
                    //任务已经存在则删除
                    scheduler.DeleteJob(jk);
                    factoryClass.JobDeletedZt(jk.Name);
                    //factoryClass.JobPaused(jk.Name);
                    //Console.WriteLine(jk.Name + ":Job任务调度删除暂停");
                    //LogHelper.WriteLog(string.Format("任务“{0}”已经删除", JobKey));
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, jk.Name + ":Job任务调度删除暂停失败", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 暂停任务
        /// </summary>
        /// <param name="JobKey"></param>
        public static void PauseJob(string name,string group)
        {
            JobKey jk = new JobKey(name, group);
            try
            {
                
                if (scheduler.CheckExists(jk))
                {
                    //任务已经存在则暂停任务
                    scheduler.PauseJob(jk);
                    factoryClass.JobPaused(jk.Name);
                    Console.WriteLine(jk.Name + ":Job任务调度暂停");
                    //LogHelper.WriteLog(string.Format("任务“{0}”已经暂停", JobKey));
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, jk.Name + ":Job任务调度暂停失败", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 暂停任务触发器
        /// </summary>
        /// <param name="JobKey"></param>
        public static void PauseTrigger(string name, string group)
        {
            TriggerKey jk = new TriggerKey(name, group);
            try
            {

                if (scheduler.CheckExists(jk))
                {
                    //任务已经存在则暂停任务
                    scheduler.PauseTrigger(jk);
                    //factoryClass.JobPaused(jk.Name);
                    Console.WriteLine(jk.Name + ":Job暂停任务触发器");
                    //LogHelper.WriteLog(string.Format("任务“{0}”已经暂停", JobKey));
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, jk.Name + ":Job暂停任务触发器失败", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 恢复运行暂停的任务
        /// </summary>
        /// <param name="JobKey">任务key</param>
        public static void ResumeJob(string name, string group)
        {
            JobKey jk = new JobKey(name, group);
            try
            {
                
                if (scheduler.CheckExists(jk))
                {
                    //任务已经存在则暂停任务
                    scheduler.ResumeJob(jk);
                    factoryClass.JobResumed(jk.Name);
                    Console.WriteLine(jk.Name + ":Job任务调度恢复");
                    //LogHelper.WriteLog(string.Format("任务“{0}”恢复运行", JobKey));
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, jk.Name + ":Job恢复任务失败", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }
        /// <summary>
        /// 恢复运行暂停的任务触发器
        /// </summary>
        /// <param name="JobKey">任务key</param>
        public static void ResumeTrigger(string name, string group)
        {
            TriggerKey jk = new TriggerKey(name, group);
            try
            {

                if (scheduler.CheckExists(jk))
                {
                    //任务已经存在则暂停任务
                    scheduler.ResumeTrigger(jk);
                    //factoryClass.JobResumed(jk.Name);
                    //Console.WriteLine(jk.Name + ":Job恢复运行暂停的任务触发器");
                    //LogHelper.WriteLog(string.Format("任务“{0}”恢复运行暂停的任务触发器", JobKey));
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, jk.Name + ":Job恢复运行暂停的任务触发器失败", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 停止任务调度
        /// </summary>
        public static void StopSchedule()
        {
            try
            {
                //判断调度是否已经关闭
                if (!scheduler.IsShutdown)
                {
                    //等待任务运行完成
                    scheduler.Shutdown(true);
                    //LogHelper.WriteLog("任务调度停止！");
                }
            }
            catch (Exception ex)
            {
                factoryClass.InsertRrrorlog(ex.Message, "任务调度停止", Quartz.Net.Model.LogsStatus.Fatal);
            }
        }

        /// <summary>
        /// 校验字符串是否为正确的Cron表达式
        /// </summary>
        /// <param name="cronExpression">带校验表达式</param>
        /// <returns></returns>
        public static bool ValidExpression(string cronExpression)
        {
            return CronExpression.IsValidExpression(cronExpression);
        }

        /// <summary>
        /// 获取任务在未来周期内哪些时间会运行
        /// </summary>
        /// <param name="CronExpressionString">Cron表达式</param>
        /// <param name="numTimes">运行次数</param>
        /// <returns>运行时间段</returns>
        public static List<DateTime> GetNextFireTime(string CronExpressionString, int numTimes)
        {
            if (numTimes < 0)
            {
                throw new Exception("参数numTimes值大于等于0");
            }
            //时间表达式
            ITrigger trigger = TriggerBuilder.Create().WithCronSchedule(CronExpressionString).Build();
            IList<DateTimeOffset> dates = TriggerUtils.ComputeFireTimes(trigger as IOperableTrigger, null, numTimes);
            List<DateTime> list = new List<DateTime>();
            foreach (DateTimeOffset dtf in dates)
            {
                list.Add(TimeZoneInfo.ConvertTimeFromUtc(dtf.DateTime, TimeZoneInfo.Local));
            }
            return list;
        }
    }
}
